<template>
  <div class="p-4 mx-auto max-w-md">
    <h2 class="mb-4 text-xl font-bold">2048 小游戏</h2>
    
    <div class="flex justify-between mb-4">
      <div class="px-4 py-2 font-bold bg-gray-100 rounded">分数: {{ score }}</div>
      <div class="px-4 py-2 font-bold bg-gray-100 rounded">最高分: {{ bestScore }}</div>
    </div>

    <div class="flex justify-between mb-4">
      <button 
        @click="newGame" 
        class="px-4 py-2 text-white bg-blue-500 rounded">
        新游戏
      </button>
      
      <div v-if="isGameOver" class="px-4 py-2 text-white bg-red-500 rounded">
        游戏结束
      </div>
      <div v-else-if="isGameWon && !keepPlaying" class="px-4 py-2 text-white bg-green-500 rounded">
        游戏胜利
      </div>
    </div>
    
    <div 
      class="relative w-full h-[400px] bg-gray-200 rounded-lg p-2"
      tabindex="0"
      @keydown.prevent="handleKeyDown"
      ref="gameContainer">
      
      <!-- 游戏网格背景 -->
      <div class="grid grid-cols-4 grid-rows-4 gap-2 w-full h-full">
        <div v-for="i in 16" :key="'bg-' + i" class="bg-gray-300 rounded"></div>
      </div>
      
      <!-- 动态方块 -->
      <div class="absolute top-2 left-2 w-[calc(100%-16px)] h-[calc(100%-16px)]">
        <div 
          v-for="tile in tiles" 
          :key="tile.id" 
          class="flex absolute justify-center items-center font-bold text-center rounded transition-all duration-100"
          :class="getTileClasses(tile.value)"
          :style="getTileStyles(tile)">
          {{ tile.value }}
        </div>
      </div>
      
      <!-- 游戏结束覆盖层 -->
      <div 
        v-if="isGameOver || (isGameWon && !keepPlaying)" 
        class="flex absolute top-0 left-0 flex-col justify-center items-center w-full h-full bg-black bg-opacity-50 rounded-lg">
        <div class="mb-4 text-2xl font-bold text-white">
          {{ isGameOver ? '游戏结束！' : '恭喜你，获胜了！' }}
        </div>
        <div v-if="isGameWon && !keepPlaying" class="flex gap-2">
          <button 
            @click="keepPlaying = true" 
            class="px-4 py-2 text-white bg-blue-500 rounded">
            继续游戏
          </button>
        </div>
      </div>
    </div>
    
    <div class="mt-4 text-sm text-gray-600">
      <p>使用 ↑ ← ↓ → 方向键或 W A S D 键移动方块。</p>
      <p>点击游戏区域以获取键盘焦点。</p>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, nextTick } from 'vue'

// 游戏状态
const score = ref(0)
const bestScore = ref(parseInt(localStorage.getItem('game2048BestScore') || '0'))
const tiles = ref([])
const grid = ref([])
const isGameOver = ref(false)
const isGameWon = ref(false)
const keepPlaying = ref(false)
const gameContainer = ref(null)
let tileIdCounter = 0

// 颜色映射
const tileClasses = {
  2: 'bg-gray-100 text-gray-800',
  4: 'bg-gray-200 text-gray-800',
  8: 'bg-orange-200 text-gray-800',
  16: 'bg-orange-300 text-white',
  32: 'bg-orange-400 text-white',
  64: 'bg-orange-500 text-white',
  128: 'bg-yellow-200 text-gray-800',
  256: 'bg-yellow-300 text-gray-800',
  512: 'bg-yellow-400 text-white',
  1024: 'bg-yellow-500 text-white',
  2048: 'bg-yellow-600 text-white',
  4096: 'bg-red-500 text-white',
  8192: 'bg-red-600 text-white',
}

// 获取方块样式
function getTileStyles(tile) {
  const cellSize = 'calc(25% - 4px)'
  return {
    width: cellSize,
    height: cellSize,
    transform: `translate(${tile.x * 100}%, ${tile.y * 100}%)`,
  }
}

// 获取方块类名
function getTileClasses(value) {
  const valueClass = tileClasses[value] || 'bg-gray-800 text-white'
  let fontSize = 'text-2xl'
  
  if (value > 512) {
    fontSize = 'text-xl'
  }
  if (value > 1024) {
    fontSize = 'text-base'
  }
  
  return `${valueClass} ${fontSize}`
}

// 初始化游戏
function initGame() {
  // 初始化4x4网格
  grid.value = Array(4).fill().map(() => Array(4).fill(null))
  tiles.value = []
  score.value = 0
  isGameOver.value = false
  isGameWon.value = false
  keepPlaying.value = false
  
  // 添加两个初始方块
  addRandomTile()
  addRandomTile()
}

// 添加随机方块
function addRandomTile() {
  const emptyCells = []
  
  // 找出所有空单元格
  for (let x = 0; x < 4; x++) {
    for (let y = 0; y < 4; y++) {
      if (!grid.value[y][x]) {
        emptyCells.push({ x, y })
      }
    }
  }
  
  // 如果没有空单元格，直接返回
  if (emptyCells.length === 0) return
  
  // 随机选择一个空单元格
  const { x, y } = emptyCells[Math.floor(Math.random() * emptyCells.length)]
  
  // 90%概率生成2，10%概率生成4
  const value = Math.random() < 0.9 ? 2 : 4
  
  // 创建新方块
  const tile = {
    id: tileIdCounter++,
    x,
    y,
    value
  }
  
  // 更新网格和方块列表
  grid.value[y][x] = tile
  tiles.value.push(tile)
}

// 检查游戏是否结束
function checkGameOver() {
  // 如果有空格，游戏未结束
  for (let y = 0; y < 4; y++) {
    for (let x = 0; x < 4; x++) {
      if (!grid.value[y][x]) return false
    }
  }
  
  // 检查水平相邻方块
  for (let y = 0; y < 4; y++) {
    for (let x = 0; x < 3; x++) {
      if (grid.value[y][x].value === grid.value[y][x + 1].value) return false
    }
  }
  
  // 检查垂直相邻方块
  for (let x = 0; x < 4; x++) {
    for (let y = 0; y < 3; y++) {
      if (grid.value[y][x].value === grid.value[y + 1][x].value) return false
    }
  }
  
  // 没有空格且没有可合并的方块，游戏结束
  return true
}

// 处理键盘事件
function handleKeyDown(e) {
  if (isGameOver.value || (isGameWon.value && !keepPlaying.value)) return
  
  let moved = false
  
  switch (e.key) {
    case 'ArrowUp':
    case 'w':
    case 'W':
      moved = moveUp()
      break
    case 'ArrowRight':
    case 'd':
    case 'D':
      moved = moveRight()
      break
    case 'ArrowDown':
    case 's':
    case 'S':
      moved = moveDown()
      break
    case 'ArrowLeft':
    case 'a':
    case 'A':
      moved = moveLeft()
      break
  }
  
  // 如果有移动，添加新方块
  if (moved) {
    addRandomTile()
    
    // 检查游戏是否结束
    if (checkGameOver()) {
      isGameOver.value = true
    }
  }
}

// 执行向上移动
function moveUp() {
  return moveTiles((x) => {
    const column = []
    // 收集列中所有方块
    for (let y = 0; y < 4; y++) {
      if (grid.value[y][x]) {
        column.push(grid.value[y][x])
      }
    }
    // 合并方块
    const merged = mergeTiles(column)
    // 更新网格
    for (let y = 0; y < 4; y++) {
      const tile = merged[y] || null
      if (tile) {
        tile.y = y
        grid.value[y][x] = tile
      } else {
        grid.value[y][x] = null
      }
    }
  })
}

// 执行向右移动
function moveRight() {
  return moveTiles((y) => {
    const row = []
    // 收集行中所有方块，从右到左
    for (let x = 3; x >= 0; x--) {
      if (grid.value[y][x]) {
        row.push(grid.value[y][x])
      }
    }
    // 合并方块
    const merged = mergeTiles(row)
    // 更新网格，从右到左
    for (let i = 0; i < 4; i++) {
      const x = 3 - i
      const tile = merged[i] || null
      if (tile) {
        tile.x = x
        grid.value[y][x] = tile
      } else {
        grid.value[y][x] = null
      }
    }
  })
}

// 执行向下移动
function moveDown() {
  return moveTiles((x) => {
    const column = []
    // 收集列中所有方块，从下到上
    for (let y = 3; y >= 0; y--) {
      if (grid.value[y][x]) {
        column.push(grid.value[y][x])
      }
    }
    // 合并方块
    const merged = mergeTiles(column)
    // 更新网格，从下到上
    for (let i = 0; i < 4; i++) {
      const y = 3 - i
      const tile = merged[i] || null
      if (tile) {
        tile.y = y
        grid.value[y][x] = tile
      } else {
        grid.value[y][x] = null
      }
    }
  })
}

// 执行向左移动
function moveLeft() {
  return moveTiles((y) => {
    const row = []
    // 收集行中所有方块
    for (let x = 0; x < 4; x++) {
      if (grid.value[y][x]) {
        row.push(grid.value[y][x])
      }
    }
    // 合并方块
    const merged = mergeTiles(row)
    // 更新网格
    for (let x = 0; x < 4; x++) {
      const tile = merged[x] || null
      if (tile) {
        tile.x = x
        grid.value[y][x] = tile
      } else {
        grid.value[y][x] = null
      }
    }
  })
}

// 通用移动函数
function moveTiles(moveFunction) {
  // 创建网格副本以检测是否有变化
  const gridCopy = grid.value.map(row => [...row])
  
  // 执行移动
  for (let i = 0; i < 4; i++) {
    moveFunction(i)
  }
  
  // 检测是否有变化
  let moved = false
  for (let y = 0; y < 4 && !moved; y++) {
    for (let x = 0; x < 4 && !moved; x++) {
      if (gridCopy[y][x] !== grid.value[y][x]) {
        moved = true
      }
    }
  }
  
  return moved
}

// 合并方块
function mergeTiles(line) {
  // 已经合并的结果
  const result = []
  
  // 处理每个方块
  for (let i = 0; i < line.length; i++) {
    const tile = line[i]
    
    // 检查是否可以与前一个方块合并
    if (result.length > 0 && result[result.length - 1].value === tile.value && !result[result.length - 1].merged) {
      // 合并方块
      const mergedTile = result[result.length - 1]
      mergedTile.value *= 2
      mergedTile.merged = true
      
      // 更新分数
      score.value += mergedTile.value
      if (score.value > bestScore.value) {
        bestScore.value = score.value
        localStorage.setItem('game2048BestScore', bestScore.value.toString())
      }
      
      // 检查是否达到2048
      if (mergedTile.value === 2048 && !isGameWon.value) {
        isGameWon.value = true
      }
      
      // 从方块列表中移除被合并的方块
      tiles.value = tiles.value.filter(t => t.id !== tile.id)
    } else {
      // 不能合并，直接添加
      result.push(tile)
    }
  }
  
  // 清除合并标记
  result.forEach(tile => {
    tile.merged = false
  })
  
  return result
}

// 开始新游戏
function newGame() {
  initGame()
  nextTick(() => {
    gameContainer.value?.focus()
  })
}

// 组件挂载时初始化游戏
onMounted(() => {
  initGame()
  nextTick(() => {
    gameContainer.value?.focus()
  })
})
</script>

<style scoped>
[tabindex="0"]:focus {
  outline: none;
}
</style> 